package cn.sw.file.service.impl;

import cn.sw.common.database.architecture.service.impl.BaseServiceImpl;
import cn.sw.common.database.domain.dto.form.AttachmentFormDto;
import cn.sw.common.database.domain.dto.query.AttachmentQueryDto;
import cn.sw.common.database.domain.entity.Attachment;
import cn.sw.common.database.domain.vo.vo.AttachmentVo;
import cn.sw.common.entity.R;
import cn.sw.file.config.MinIOConfigInfo;
import cn.sw.file.mapper.AttachmentMapper;
import cn.sw.file.service.AttachmentService;

import io.minio.GetObjectArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.errors.*;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;


import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;


/**
 * 附件表 服务实现类
 *
 * @author 张众森 (个人博客:https://)
 * @date 2025-05-23
 * @tags 做一个优秀的全栈架构
 */
@Service
public class AttachmentServiceImpl extends BaseServiceImpl<AttachmentMapper, Attachment, AttachmentFormDto, AttachmentQueryDto, AttachmentVo> implements AttachmentService {

    @Resource
    private MinioClient minioClient;

    @Resource
    private MinIOConfigInfo minIOConfigInfo;

    @Resource
    AttachmentService attachmentService;

    public R<String> uploadFile(MultipartFile file) throws IOException {
        //处理文件，对文件进行重命名并上传到 minio
        String originalFilename = file.getOriginalFilename(); // 原始文件全称
        String suffix = "";//文件后缀
        if (originalFilename != null && originalFilename.contains(".")) {
            suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
        }
        String uuid = java.util.UUID.randomUUID().toString().replace("-", ""); // 重命名文件名存储到 minio，防止上传的文件名重复
        String renameFile = uuid + "." + suffix;
        // 上传至 minio
        LocalDateTime now = LocalDateTime.now();
        // 文件以年月日的格式分文件夹存储
        String minioFileName = now.getYear() + "/" + now.getMonthValue() + "/" + now.getDayOfMonth() + "/" + renameFile;
        try {
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(minIOConfigInfo.getBucketName())
                    .object(minioFileName)
                    .contentType(file.getContentType())
                    .stream(file.getInputStream(), file.getSize(), -1)
                    .build()
            );
        } catch (ErrorResponseException e) {
            throw new RuntimeException(e);
        } catch (InsufficientDataException e) {
            throw new RuntimeException(e);
        } catch (InternalException e) {
            throw new RuntimeException(e);
        } catch (InvalidKeyException e) {
            throw new RuntimeException(e);
        } catch (InvalidResponseException e) {
            throw new RuntimeException(e);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        } catch (ServerException e) {
            throw new RuntimeException(e);
        } catch (XmlParserException e) {
            throw new RuntimeException(e);
        }
        // 插入文件数据到表中
        AttachmentFormDto form = new AttachmentFormDto();
        form.setOriginFileName(originalFilename);
        form.setBucket(minIOConfigInfo.getBucketName());
        form.setMinioFileName(minioFileName);
        attachmentService.C(form);
        // 生成图片 url 地址
        // String url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
        //         .bucket(minIOConfigInfo.getBucket())
        //         .minioFileName(path)
        //         .expiry(1, TimeUnit.MILLISECONDS)
        //         .method(Method.GET)
        //         .build());
        // return R.ok(url);

        // 如果设置了公开只读访问策略，则可以不经过getPresignedObjectUrl生成签名，直接访问即可
        return R.ok(minIOConfigInfo.getEndpoint() + "/" + minIOConfigInfo.getBucketName() + "/" + minioFileName);
    }

    @Override
    public void downloadFile(String id, HttpServletResponse response) {
        Attachment attachment = this.getById(id);

        if (attachment == null) {
            // 抛出自定义异常或返回错误响应
            try {
                response.sendError(HttpServletResponse.SC_NOT_FOUND, "文件不存在");
            } catch (IOException e) {
                e.printStackTrace();
            }
            return;
        }

        // 设置响应头，强制浏览器下载
        response.setContentType("application/octet-stream");
        response.setCharacterEncoding("UTF-8");
        String fileName = attachment.getOriginFileName(); // 使用原始文件名下载
        try {
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("设置文件名编码失败", e);
        }

        // 从 MinIO 获取文件输入流
        try (InputStream inputStream = minioClient.getObject(
                GetObjectArgs.builder()
                        .bucket(attachment.getBucket())
                        .object(attachment.getMinioFileName())
                        .build())) {

            // 将文件内容写入响应输出流
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                response.getOutputStream().write(buffer, 0, bytesRead);
            }

        } catch (Exception e) {
            throw new RuntimeException("文件下载失败: " + e.getMessage(), e);
        }
    }

}



